home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / OS Utilities / SetLED / SetLED.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-30  |  7.2 KB  |  219 lines  |  [TEXT/CWIE]

  1. /*
  2.     file:    SetLED.c
  3.             Sample program to demonstrate the use of the ADBOp call, including use
  4.             of the completion routine under 68K, CFM68K, and PPC.
  5.             
  6.             demonstrates a workaround for a bug with the CFM68K InterfaceLib glue
  7.             code such that a call to ADBOp under CFM68K results in a bus error.
  8.             This bug was identified with MacOS 8.1 running on different 68040 CPU's
  9.             
  10.     By: Rich Kubota    4/7/98
  11.         Macintosh Developer Support
  12.         
  13. */
  14.  
  15. #include <Types.h>
  16. #include <Events.h>
  17. #include <OSUtils.h>
  18. #include <DeskBus.h>
  19. #include <MixedMode.h>
  20.  
  21.  
  22. // keyboard ADB constants           
  23. #define kTalkCommand    8+4         
  24. #define kListenCommand  8           
  25. #define kLEDRegister    2       
  26.  
  27. #if TARGET_CPU_68K && !TARGET_RT_MAC_CFM
  28. pascal long    GetA2( void )    ONEWORDINLINE(0x2E8A);
  29. #endif     //  TARGET_CPU_68K && !TARGET_RT_MAC_CFM
  30.  
  31. static long             gCompletionFlag;
  32. static ADBServiceRoutineUPP completionProc;                    
  33. static pascal void CompADBOp(void);
  34.  
  35. pascal OSErr MyADBOp(Ptr refCon, ADBServiceRoutineUPP compRout, 
  36.                             Ptr buffer, short commandNum);
  37.  
  38. // example completion routine for use with ADBOp
  39. pascal void CompADBOp(void)
  40. #if TARGET_CPU_PPC || TARGET_RT_MAC_CFM
  41.     // Under, we can access global variables which is simpler
  42.     // than trying to write the glue code required so that 
  43.     // the completion routine is called with the registers
  44.     // set as per Inside Mac V-368
  45.     // set flag to indicate completion routine has completed
  46.     gCompletionFlag = 1;
  47. #else  // TARGET_CPU_PPC || TARGET_RT_MAC_CFM
  48.  
  49.     // under 68K, but not CFM-68K, all of the arguments are passed
  50.     // in registers so we use inline functions to access those
  51.     // arguments.  In this sample, the optional data
  52.     // buffer argument is interest since we want to set a boolean flag to 
  53.     // indicate that the completion routine has been executed.  A similar
  54.     // macro as that for GetA2 can be written to access the command buffer
  55.     // pointer in register A0
  56.     long     *completionFlagPtr;
  57.  
  58.     // set flag to indicate completion routine has run; A2 points to the flag
  59.     completionFlagPtr = (long*)GetA2(); 
  60.     *completionFlagPtr = 1;
  61. #endif  // TARGET_CPU_PPC || TARGET_RT_MAC_CFM
  62. } /* end of CompADBOp */
  63.  
  64. #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
  65. // The following code is implemented to fix a bug that exists with the 
  66. // 68K InterfaceLib glue code.  In order for the glue code to work, 
  67. // a pointer to an ADBOpBlock structure must be passed in register A0.
  68. // We define the global ADBOpBlock structure to support
  69. // the asynch ADBOp call
  70.  
  71. ADBOpBlock    gADBOpBlock;
  72. #endif     //  TARGET_CPU_68K && TARGET_RT_MAC_CFM
  73.  
  74. // Instead of making the ADBOp directly, call MyADBOp which makes 
  75. // the appropriate call depending on the target architecture.
  76. // For CFM68K, the ADBOpBlock structure is filled in and the
  77. // ADBGlue routine above is called. For regular 68K and PPC, the
  78. // ADBOp call is made straightaway.
  79.  
  80. pascal OSErr MyADBOp(
  81.      Ptr refCon,
  82.      ADBServiceRoutineUPP compRout,
  83.      Ptr buffer,
  84.      short commandNum)
  85. {
  86. #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
  87.     ADBOpBlock    adbOpBlock;
  88.  
  89.     adbOpBlock.dataBuffPtr = buffer;
  90.     adbOpBlock.opServiceRtPtr = compRout;
  91.     adbOpBlock.opDataAreaPtr = refCon;
  92.     
  93.     // Important Note: In this sample, we declare the adbOpBlock
  94.     // structure as a stack variable.  Normally it is bad practice
  95.     // to use a stack parameter for any asynchronous call.
  96.     // ADBOp makes a copy of the contents of the structure so the
  97.     // structure does not need to exist for the life of the 
  98.     // asynchronous call.
  99.  
  100.     // Note that the refCon value is placed into the ADBOpBlock
  101.     // structure for completeness.
  102.     // This program sample assumes that a completion routine, under
  103.     // CFM, will access the refCon and the data buffer as globals
  104.     // to the process, since under CFM, this is possible.
  105.     // Otherwise, more glue code is required so that when CFM calls
  106.     // the completion routine, the 68K registers will be set as
  107.     // per Inside Mac V-368.
  108.     
  109.     return (OSErr) CallUniversalProc((UniversalProcPtr)NGetTrapAddress(0xA07C, 0),
  110.             kRegisterBased |
  111.             RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
  112.             REGISTER_RESULT_LOCATION(kRegisterD0) |
  113.             REGISTER_ROUTINE_PARAMETER(1,
  114.                 kRegisterA0, SIZE_CODE(sizeof(&gADBOpBlock))) |
  115.             REGISTER_ROUTINE_PARAMETER(2,
  116.                 kRegisterD0, SIZE_CODE(sizeof(commandNum))),
  117.             &gADBOpBlock,
  118.             commandNum);
  119. #else  // TARGET_CPU_68K && TARGET_RT_MAC_CFM
  120.      return (ADBOp(refCon, compRout, buffer, commandNum));
  121. #endif  // TARGET_CPU_68K && TARGET_RT_MAC_CFM
  122. }
  123.  
  124. // set the leds to the given pattern }
  125. static void kb_SetMacNumLockLED( Boolean ledOn )
  126. {
  127.     OSErr               retCode;
  128.     ADBAddress          anADBadd;       // address of each device
  129.     Byte                regBuff[9];     // buffer for ADBOp commands
  130.     Byte                oldReg;
  131.     Byte                LEDPattern;
  132.     
  133.     if ( ledOn )
  134.         LEDPattern = 0x07;
  135.     else
  136.         LEDPattern = 0x00;
  137.     
  138.     // get an address for an ADB device - here we just talk to whatever keyboard
  139.     // is at ADB Address 2.  A more complete program might check the type of
  140.     // keyboard present to ensure that it has an LED present.
  141.     anADBadd = 2;
  142.     
  143.     regBuff[0] = (Byte)0; // initial data buffer length
  144.     regBuff[1] = 0;
  145.     regBuff[2] = 0;
  146.  
  147.     // initialize the completion flag so that we will know when the ADBOp call
  148.     // has completed.
  149.     gCompletionFlag = 0;
  150.     
  151.     retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
  152.                                 kTalkCommand + kLEDRegister + 16 * anADBadd );
  153.     
  154.     if ( retCode != noErr )         // queue was full, try again
  155.     {
  156.         gCompletionFlag = 0;
  157.         retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
  158.                                     kTalkCommand + kLEDRegister + 16 * anADBadd );
  159.         
  160.         if ( retCode != noErr )         // queue was still full, give up
  161.             return;
  162.     }
  163.     
  164.     // do nothing until completion routine has run
  165.     do
  166.     {
  167.     }
  168.     while ( ! gCompletionFlag );
  169.             
  170.     regBuff[0] = (Byte)2; // initial data buffer length
  171.     // extended keyboard has a word of data, LEDs are low 3 bits
  172.     oldReg = regBuff[2];
  173.     
  174.     // set the specified bits; note that a clear bit indicates a lit LED
  175.     // note that if LEDpattern is 7, then all three LED's will enable.
  176.     regBuff[2] = (oldReg & 255-7) | (7 - LEDPattern);
  177.  
  178.     // initialize the completion flag so that we will know when the ADBOp call
  179.     // has completed.
  180.     gCompletionFlag = 0;                        
  181.  
  182.     retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
  183.                                 kListenCommand + kLEDRegister + 16 * anADBadd );
  184.  
  185.     if (retCode != noErr)
  186.         DebugStr("\p error on ADBOp for listen");
  187.     else
  188.     {
  189.             // do nothing until completion routine has run
  190.         do
  191.         {
  192.         }
  193.         while ( ! gCompletionFlag );
  194.     }
  195.  
  196. } /* end of kb_SetMacNumLockLED */
  197.  
  198.  
  199. void main (void)
  200. {
  201.     unsigned long    dummy;
  202.     short    i;
  203.  
  204.     completionProc = NewADBServiceRoutineProc( CompADBOp );
  205.  
  206.     i = 0;
  207.         // press the button to quit the test
  208.     while (!Button())
  209.     {
  210.         i++;
  211.         kb_SetMacNumLockLED(i % 2);
  212.         Delay(15, &dummy);
  213.     }
  214.  
  215.     if (completionProc != nil)
  216.         DisposeRoutineDescriptor( completionProc );
  217. }
  218.